﻿package datastore
         
import (  
    "io"
    "bufio"     
    "bytes"
    //"io/ioutil"             
    "encoding/binary"   
    "time"    
    "fmt"
    "os"        
    "common/file"
    //"common/sysutils" 
)  
  
type DayHeader struct { 
    Signature        uint16                 
    DataVer1         byte
    DataVer2         byte
    DataVer3         byte
    BytesOrder       byte
    HeadSize         byte             // 1 -- 7
    StoreSizeMode    byte  // 1 -- 8 page size mode
    DataType         uint16             // 2 -- 10
    DataMode         byte             // 1 -- 11
    RecordSizeMode   byte  // 1 -- 12
    RecordCount      int32          // 4 -- 16
    CompressFlag     byte             // 1 -- 17
    EncryptFlag      byte             // 1 -- 18
    DataSourceId     uint16             // 2 -- 20
    Code             []byte 
    StorePriceFactor uint16             // 2 - 34   
    FirstDealDate    uint16             // 2 - 36
    LastDealDate     uint16             // 2 - 38
    EndDealDate      uint16             // 2 - 40
}
         
func NewDayHead(buf []byte)*DayHeader{
    head := new(DayHeader) 
    // ------------------------------------
    // common header
    //head.Signature      = binary.BigEndian.Uint16(buf[0:2])
    head.Signature      = binary.LittleEndian.Uint16(buf[0:2])
    head.HeadSize       = buf[6]
    head.StoreSizeMode  = buf[7]
    head.DataType       = binary.LittleEndian.Uint16(buf[8:10])
    head.DataMode       = buf[10]
    head.RecordSizeMode = buf[11]

    byte_buf := bytes.NewBuffer(buf[12:16])
    binary.Read(byte_buf, binary.LittleEndian, &head.RecordCount)

    //binary.Write(buf[8:12], binary.BigEndian, head.RecordCount)
    //binary.Read(buf[8:12], binary.BigEndian, &head.RecordCount)

    head.CompressFlag   = buf[16]
    head.EncryptFlag    = buf[17]
    head.DataSourceId   = binary.LittleEndian.Uint16(buf[18:20])
    // ------------------------------------              
    //head.Code              = make([]byte, 12)
    head.Code              = bytes.Repeat(buf[20:32], 1)
    head.StorePriceFactor  = binary.LittleEndian.Uint16(buf[32:34])
    // ------------------------------------              
    return head
}

/*         
  PStore_Quote64_Day    = ^TStore_Quote64_Day;
  TStore_Quote64_Day    = packed record  // 56
    PriceRange          : TStore_PriceRange;  // 16
    DealVolume          : Int64;         // 8 - 24 成交量
    DealAmount          : Int64;         // 8 - 32 成交金额
    DealDate            : Integer;       // 4 - 36 交易日期
    Weight              : TStore_Weight; // 4 - 40 复权权重 * 100
    TotalValue          : Int64;         // 8 - 48 总市值
    DealValue           : Int64;         // 8 - 56 流通市值
  end;
*/
type DayRecord struct {  
    PriceOpen           int32  // 4 - 4
    PriceHigh           int32  // 4 - 8  ( price * 100 )
    PriceLow            int32  // 4 - 12
    PriceClose          int32  // 4 - 16
    DealVolume          int64  // 8 - 24 成交量
    DealAmount          int64  // 8 - 32 成交金额
    DealDate            int32  // 4 - 36 交易日期
    Weight              int32     // 4 - 40 复权权重 * 100
    TotalValue          int64         // 8 - 48 总市值
    DealValue           int64         // 8 - 56 流通市值
}
        
func NewDayRecord(buf []byte)*DayRecord{
    dayrec := new(DayRecord) 
    byte_buf := bytes.NewBuffer(buf[0:4])
    binary.Read(byte_buf, binary.LittleEndian, &dayrec.PriceOpen)
    
    byte_buf = bytes.NewBuffer(buf[4:8])
    binary.Read(byte_buf, binary.LittleEndian, &dayrec.PriceHigh)

    byte_buf = bytes.NewBuffer(buf[8:12])
    binary.Read(byte_buf, binary.LittleEndian, &dayrec.PriceLow)

    byte_buf = bytes.NewBuffer(buf[12:16])
    binary.Read(byte_buf, binary.LittleEndian, &dayrec.PriceClose)

    byte_buf = bytes.NewBuffer(buf[32:36])
    binary.Read(byte_buf, binary.LittleEndian, &dayrec.DealDate)

    // ------------------------------------
    return dayrec
}
  
func delphiDate2Date_i32(delphiDate int32) string {
    var unixdatetime int64 = int64(delphiDate);
    unixdatetime = unixdatetime - 25569;
    unixdatetime = unixdatetime * 60 * 60 * 24;
    str_time := time.Unix(unixdatetime, 0).Format("2006-01-02 15:04:05")
    //str_time := time.Unix(1389058332, 0).Format("2006-01-02 15:04:05")
    return str_time;
}
          
var (
  stockfileurl = "E:\\StockApp\\sdata\\d163\\600000.d_32"
)

func LoadDayData() {
  LoadDayDataFromFile(stockfileurl)
}

func LoadDayDataFromFile(fileurl string) {
    // f, err := os.OpenFile("test.txt", os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm|os.ModeTemporary)
    f, err := os.Open(fileurl)//打开文件
    defer f.Close() //打开文件出错处理
    if nil == err {
        filereader := bufio.NewReader(f) //读入缓存
                                     
        buff_day := make([]byte, 64)
        buff_header := make([]byte, 64)
        filereader.Read(buff_header)
                         
        head := NewDayHead(buff_header)
        fmt.Printf("Signature: %d\n", head.Signature)    
        fmt.Printf("HeadSize: %d\n", head.HeadSize)
        fmt.Printf("StoreSizeMode: %d\n", head.StoreSizeMode)
        fmt.Printf("DataType: %d\n", head.DataType)          
        fmt.Printf("DataMode: %d\n", head.DataMode)
        fmt.Printf("RecordSizeMode: %d\n", head.RecordSizeMode)
        fmt.Printf("recordcount: %d\n", head.RecordCount)      
        fmt.Printf("CompressFlag: %d\n", head.CompressFlag)    
        fmt.Printf("EncryptFlag: %d\n", head.EncryptFlag)
        fmt.Printf("DataSourceId: %d\n", head.DataSourceId)   
        fmt.Printf("Code: %s\n", string(head.Code))
        fmt.Printf("StorePriceFactor: %d\n", head.StorePriceFactor)     
        fmt.Printf("=============================================\n")
        rowindex := 0;
        for {
            readsize, _ := filereader.Read(buff_day)
            if 0 < readsize {
                rowindex++
                fmt.Printf("line%d %d\n", rowindex, readsize) 
                daydata := NewDayRecord(buff_day)
                                                    
                fmt.Printf("PriceOpen: %d\n", daydata.PriceOpen)
                fmt.Printf("PriceHigh: %d\n", daydata.PriceHigh)
                fmt.Printf("PriceLow: %d\n", daydata.PriceLow)
                fmt.Printf("PriceClose: %d\n", daydata.PriceClose)
                fmt.Printf("DealDate: %s\n", delphiDate2Date_i32(daydata.DealDate))
                fmt.Printf("-----\n")
                if 10 < rowindex {
                    break
                }
            } else {
                fmt.Printf("end!")
                break
            }
        }
    }
}

func SaveDayData() {
  //SaveDayDataToFile("E:\\StockApp\\test.dat")
  SaveDayDataToFile("./output1.txt")
}

func SaveDayDataToFile(fileurl string) {
  var filehandle *os.File
  var err error;
  filexist := file.IsFileExist(fileurl)
  if filexist {   
    fmt.Printf("file is exists\n")
    filehandle, err = os.OpenFile(fileurl, os.O_APPEND, 0666)  //打开文件
  } else {
    fmt.Printf("file is not exists\n")
    filehandle, err = os.Create(fileurl)  //创建文件
  }
  checkError(err);

  n, err := io.WriteString(filehandle, "hello\r\n") //写入文件(字符串)
  checkError(err)
  fmt.Printf("写入 %d 个字节\n", n);
                                       
  //-----------------------------------
  // 另外一种写入模式
  /*
  var byteswrite = []byte("bytes write mode");
  err = ioutil.WriteFile("./output2.txt", byteswrite, 0666)  //写入文件(字节数组)
  checkError(err)
  //*/
  //-----------------------------------
  /*
  filehandle, err = os.Create("./output3.txt")  //创建文件
  checkError(err)
  defer filehandle.Close()
  var byteswrite = []byte("bytes write mode\r\n");
  n, err = filehandle.Write(byteswrite)  //写入文件(字节数组)
  checkError(err)
  fmt.Printf("写入 %d 个字节\n", n)
  n, err = filehandle.WriteString("writesn") //写入文件(字节数组)
  fmt.Printf("写入 %d 个字节\n", n)
  filehandle.Sync()
  //*/        
  //-----------------------------------  
  /*
  filewriter := bufio.NewWriter(filehandle)  //创建新的 Writer 对象
  n, err = filewriter.WriteString("buffered\n")
  fmt.Printf("写入 %d 个字节\n", n)
  filewriter.Flush()
  filehandle.Close()      
  //*/        
  //-----------------------------------  
}

func checkError(e error) {
  if nil != e {
    panic(e)
  }
}  
